go通道channel 死锁的场景和原因浅析

您所在的位置:网站首页 go 协程 channel go通道channel 死锁的场景和原因浅析

go通道channel 死锁的场景和原因浅析

2023-04-24 08:58| 来源: 网络整理| 查看: 265

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

通道简介

go的通道channel是用于协程之间数据通信的一种方式,因为协程goroutine在运行的时候不保证顺序,且是并发(非并行)执行,数据的传递要么通过共享内存(比如指针)传递,要么就是通过一个额外的channel来传递。 其实推荐使用channel来传递数据主要是:

1.避免协程竞争和数据冲突问题,大家都去抢那个共享内存的指针是有冲突的,同时修改又有并发问题,还需要加锁 2.更高级抽象,降低开发难度,管道通信是一种通信方式,只需要监听即可,无需多次轮训来耗费资源 3.模块之间更容易解耦,增加扩展性和可维护性,通道有时候更像是生产者消费者模式,产生数据的协程和接受数据的协程无需知晓对方的存在,只专注自己的事就好

通道长啥样 type hchan struct {      qcount   uint                 dataqsiz uint               buf      unsafe.Pointer       elemsize uint16      closed   uint32      elemtype *_type       sendx    uint         recvx    uint         recvq    waitq        sendq    waitq        lock mutex     } 复制代码 qcount  channel 中的元素个数 dataqsiz channel 中循环缓存队列的长度 buf channel中缓存区的指针 elemsize channel收发(元素)的大小 elemtype channel收发(元素)的类型 closed 通道关闭的flag,一旦关闭将不能接受新的消息 sendx sendq,发送队列的指针和发送队列 recvx recvq ,接收队列的指针和接收队列 lock 锁,保护整个结构体

通道channel主要是设置了一个环状的缓冲区,其实就是个环形链表,好处就是降低gc的开销,缓冲区的大小是创建channel的时候传入的。当没有设置缓冲区的时候,缓冲区为0,这时候称该通道为无缓冲通道,反之就是有缓冲的通道。 关于两者的区别主要是在阻塞的过程上有差别。

对于无缓冲区的channel 发送数据方在发送的时候,如果没有接收者,那么发送方的协程groutine阻塞在通道的sendq里面。 接收数据方会一直等待数据到来,如果数据一直没有到来,那么接收方的协程groutine就会阻塞在channel的recvq里面。 对于有缓冲区的channel 在缓冲区没有满的时候,发送方只管发送,当缓冲区存满的时候,发送方的协程groutine就会阻塞,如果这时候有协程过来取数据,那么优先给他缓存里的数据,然后再把sendq里面的协程的数据copy到缓存,并把该协程从阻塞中释放出来,也就是唤醒。 当缓冲区没有任何数据,也就是管道里面没有数据的时候,接收方就因为取不到数据而阻塞,进入到recvq里面等待数据到来。当数据到的时候,发送方的协程直接把数据cpoy给接收方的协程,不需额外的经过一次缓冲区。 死锁场景

1. 没有缓冲区的时候,单协程内通道同时写和读

func main() { // 创建一个通道 ch := make(chan int) ch


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3